/*
 * Copyright (c) 2012 Craig Weinhold (cweinhold@gmail.com)
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */


#ifndef _SEQUENCE_H
#define _SEQUENCE_H

#include <stdint.h>
#include <sys/types.h>

#include "flowd-common.h"
#include "flowd.h"
#include "sys-queue.h"
#include "sys-tree.h"
#include "peer.h"

#define MAX_SEQUENCE_ENTRIES	12			/* how many out-of-order/lost sequence numbers to track */
#define MAX_SOURCES		5			/* how many different source_id's allowed from any given peer */

#define SEQUENCE_WINDOW_V9	12			/* exactly 12 packets */
#define SEQUENCE_WINDOW_V5	360			/* about 12 packets */

struct engine {
	u_int8_t		unused1;
	u_int8_t		unused2;
	u_int8_t		engine_type;
	u_int8_t		engine_id;
};

struct sourceinfo {
	u_int16_t version;
	union {
		u_int32_t		source_id;
	        struct engine		engine_info;
	} xs;
};

struct source_state {
	SPLAY_ENTRY(source_state) tp;
	TAILQ_ENTRY(source_state) lp;

	struct sourceinfo sourceinfo;
	unsigned int entries;
	unsigned int window;
	u_int64_t nlost;
	u_int64_t npackets;
	u_int64_t nflows;
	u_int64_t nwindowfail;
	u_int64_t nreset;
	u_int64_t ndup;
	uint32_t seqnum[MAX_SEQUENCE_ENTRIES];
	uint32_t nextnum[MAX_SEQUENCE_ENTRIES];
};

SPLAY_HEAD(source_tree, source_state);
TAILQ_HEAD(source_list, source_state);

struct seqinfo {
        u_int num_sources;
        struct source_tree source_tree;
        struct source_list source_list;
};

/* Source state handling functions */

static int source_compare(struct source_state *a, struct source_state *b);

struct source_state *find_source(struct seqinfo *seq, struct sourceinfo *si);

struct source_state *new_source(struct seqinfo *seq, struct sourceinfo *si);

void sequence_v5(struct peer_state *peer, uint32_t sequence, uint32_t nflows, uint8_t engine_type, uint8_t engine_id);

void sequence_v7(struct peer_state *peer, uint32_t sequence, u_int nflows);

void sequence_v9(struct peer_state *peer, uint32_t sequence, uint32_t source_id, uint32_t nflows);

void sequence_update(struct peer_state *peer, uint32_t sequence, u_int length,
		uint32_t num_packets, uint32_t num_flows,
		struct sourceinfo *si);


#endif		/* _SEQUENCE_H */

